﻿using K9Nano.Dependency;
using Microsoft.Extensions.Options;

namespace K9Nano.Captcha;

internal class CaptchaManager(ICaptchaGenerator generator, ICaptchaStore store, IOptions<K9Options> optionsAccessor) : ICaptchaManager, ISingletonDependency
{
    private const string Alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZ";

    private const string AlphabetDigital = "ABCDEFGHJKLMNPQRSTUVWXYZ0123456789";


    /// <inheritdoc/>
    public CaptchaInfo GenerateImage(string requestId, TimeSpan expire, int length)
    {
        var code = GenerateCode(requestId, expire, length);
        var data = generator.Generate(code);
        return new CaptchaInfo(code, data);
    }

    /// <inheritdoc/>
    public string GenerateCode(string requestId, TimeSpan expire, int length)
    {
        var code = RandomCode(length);
        store.Save(requestId, code, expire);
        return code; ;
    }

    /// <inheritdoc/>
    public bool Validate(string requestId, string code)
    {
        var storedCode = store.Get(requestId);
        var result = code.Equals(storedCode, StringComparison.OrdinalIgnoreCase);
        store.Remove(requestId);
        return result;
    }

    private string RandomCode(int length)
    {
#if DEBUG
        if (!string.IsNullOrEmpty(optionsAccessor.Value.FrozenCaptcha))
        {
            return optionsAccessor.Value.FrozenCaptcha;
        }
#endif
        string chars;
        switch (optionsAccessor.Value.CaptchaType)
        {
            case "Digital":
                return Random.Shared.NextDouble().ToString().Substring(2, length);
            case "Alphabet":
                chars = Alphabet;
                break;
            default:
                chars = AlphabetDigital;
                break;
        }

        var code = new char[length];
        for (var i = 0; i < length; i++)
        {
            code[i] = chars[Random.Shared.Next(chars.Length)];
        }
        return new string(code);
    }
}
